package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author tongatong
 * @name OrderServiceImpl
 * @description
 * @date 2021/9/25
 * @time 11:24
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
    @Resource
    private OrderInfoMapper orderInfoMapper;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Value("${ware.url}")
    private String WARE_URL;
    @Resource
    private RabbitService rabbitService;


    @Override
    public Long saveOrderInfo(OrderInfo orderInfo) {
        //这里需要对要提交的订单信息，进行一些补充
        //前台传过来的：consignee, consignee_tel, total_amount, payment_way，delivery_address，order_comment
        //需要补充的：user_id(controller中已经获取并赋值), order_status,order_comment，out_trade_no，trade_body，
        // operate_time，expire_time，process_status等等
        //总金额
        orderInfo.sumTotalAmount();
        //订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //订单编号
        //先生成订单编号
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        //订单编号赋值
        orderInfo.setOutTradeNo(outTradeNo);
        //订单创建时间
        orderInfo.setCreateTime(new Date());
        //设置失效时间，下单时间+1天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());
/*        //使用jdk8的时间类
        //先获取当前时间+1天
        LocalDateTime now = LocalDateTime.now().plusDays(1);
        //转化为时间戳,这里注意时区
        Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
        Date from = Date.from(instant);
        orderInfo.setExpireTime(from);*/
        //设置订单进程状态，默认未支付
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        // 获取订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        StringBuffer tradeBody = new StringBuffer();
        orderDetailList.forEach(orderDetail -> tradeBody.append(orderDetail.getSkuName()).append(" "));
        //这里显示有长度限制，因此需要判断
        if (tradeBody.toString().length()>100){
            orderInfo.setTradeBody(tradeBody.toString().substring(0,100));
        }else {
            orderInfo.setTradeBody(tradeBody.toString());
        }
        //调用保存订单信息方法
        orderInfoMapper.insert(orderInfo);
        //订单详情，即订单中的商品信息
        orderDetailList.forEach(orderDetail -> {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        });

        //发送延迟队列，如果定时未支付，取消订单
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL, MqConst.ROUTING_ORDER_CANCEL, orderInfo.getId(), MqConst.DELAY_TIME);

        return orderInfo.getId();
    }

    @Override
    public String getTradeNo(String userId) {
        //定义保存流水号的key
        String tradeNoKey = "user:" + userId + ":tradeCode";
        // 生成流水号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);
        return tradeNo;
    }

    @Override
    public boolean checkTradeCode(String userId, String tradeCodeNo) {
        //定义流水号key
        String tradeNoKey = "user:" + userId + ":tradeCode";
        //从redis中获取到key对应的value
        String redisTradeNo = redisTemplate.opsForValue().get(tradeNoKey);
        //比较是否一致
        return tradeCodeNo.equals(redisTradeNo);

    }

    @Override
    public void deleteTradeNo(String userId) {
        //定义key
        String tradeNoKey = "user:" + userId + ":tradeCode";
        //删除数据，当第一次比较相等之后，删除redis中的key，以防止再次提交订单
        redisTemplate.delete(tradeNoKey);
    }

    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        //因为第三方仓库系统并不是cloud系统，因此不能使用feign进行远程调用，feign是cloud组件
        //在提交订单的时候，需要验证库存是否足够
        // 远程调用http://localhost:9001/hasStock?skuId=10221&num=2
        String result = HttpClientUtil.doGet(WARE_URL + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);

    }

    @Override
    public IPage<OrderInfo> getPage(Page<OrderInfo> pageParam, String userId) {
        IPage<OrderInfo> page = orderInfoMapper.selectPageByUserId(pageParam, userId);
        page.getRecords().forEach(item -> {
            item.setOrderStatusName(OrderStatus.getStatusNameByStatus(item.getOrderStatus()));
        });
        return page;

    }

    @Override
    public void execExpiredOrder(Long orderId) {
        //取消订单，并不是删除订单信息，而是更新订单的某些信息
        //这里抽象出一个专门更新订单状态的方法，是因为，往后可能还有修改订单的状态
        //比如订单支付完成后，也需要修改订单状态
        updateOrderStatus(orderId, ProcessStatus.CLOSED);

        //当订单长时间不支付的时候，需要取消该订单，这里通过rabbimq取消订单
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE, MqConst.ROUTING_PAYMENT_CLOSE, orderId);
    }

    @Override
    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        //根据订单id，修改订单进程和订单状态的信息
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setProcessStatus(processStatus.name());
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setUpdateTime(new Date()) ;
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(queryWrapper);
        orderInfo.setOrderDetailList(orderDetailList);
        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        this.updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);

        String wareJson = initWareOrder(orderId);
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK, MqConst.ROUTING_WARE_STOCK, wareJson);

    }
    // 根据orderId 获取json 字符串
    private String initWareOrder(Long orderId) {
        // 通过orderId 获取orderInfo
        OrderInfo orderInfo = getOrderInfo(orderId);

        // 将orderInfo中部分数据转换为Map
        Map<String, Object> map = initWareOrder(orderInfo);

        return JSON.toJSONString(map);
    }

    @Override
    //  将orderInfo中部分数据转换为Map
    public Map<String, Object> initWareOrder(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
    /*
    details:[{skuId:101,skuNum:1,skuName:
    ’小米手64G’},
    {skuId:201,skuNum:1,skuName:’索尼耳机’}]
     */
        ArrayList<Map<String, Object>> mapArrayList = new ArrayList<>();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId", orderDetail.getSkuId());
            orderDetailMap.put("skuNum", orderDetail.getSkuNum());
            orderDetailMap.put("skuName", orderDetail.getSkuName());
            mapArrayList.add(orderDetailMap);
        }
        map.put("details", mapArrayList);
        return map;
    }

    @Override
    public List<OrderInfo> orderSplit(long orderId, String wareSkuMap) {
        /*
        拆单操作，因为所买的商品可能不在同一个仓库中，所以需要根据仓库的不同，分为不同的子订单，
        父订单的id为原来的大订单id。
        首先获取到原来的订单仓库信息，在wareSkuMap中，格式为：[{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        然后根据key划分不同的子订单，并为子订单的内容赋值，如重新计算订单价格等。
         */
        //存储所有的子订单
        List<OrderInfo> orderInfoArrayList = new ArrayList<>();
        //先获取原来的订单信息
        OrderInfo orderInfoOrigin = getOrderInfo(orderId);
        //将wareSkuMap字符串，转化为可操作性的类，JSON-》class,这里本来是一个数组，需要转换为list集合
        List<Map> maps = JSON.parseArray(wareSkuMap, Map.class);
        if (!maps.isEmpty()) {
            maps.forEach(map -> {
                //仓库id
                String wareId = (String) map.get("wareId");
                //子订单中包含的购物项
                List<String> skuIds = (List<String>) map.get("skuIds");
                OrderInfo subOrderInfo = new OrderInfo();
                //属性拷贝,将父订单的所有订单信息赋值给子订单
                BeanUtils.copyProperties(orderInfoOrigin, subOrderInfo);
                //重新设置子订单的订单id，防止主键冲突
                subOrderInfo.setId(null);
                //父订单id
                subOrderInfo.setParentOrderId(orderId);
                //赋值仓库Id
                subOrderInfo.setWareId(wareId);

                //重新计算子订单的金额
                //先获取订单购物项的详情信息，因为可能有多个商品，所以需要一个集合
                List<OrderDetail> orderDetails = new ArrayList<>();
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
                if (!orderDetailList.isEmpty()) {
                    //遍历父订单中，每个购物项
                    for (OrderDetail orderDetail : orderDetailList) {
                        skuIds.forEach(skuId -> {
                            //商品id包含在子订单中的话，就添加到子订单购物项集合中
                            if (skuId.equals(orderDetail.getId().toString())) {
                                // 将订单明细添加到集合
                                orderDetails.add(orderDetail);
                            }
                        });
                    }
                }
                //更新子订单的购物项
                subOrderInfo.setOrderDetailList(orderDetails);
                //计算总金额
                subOrderInfo.sumTotalAmount();
                //保存子订单
                saveOrderInfo(subOrderInfo);
                // 将子订单添加到集合中！
                orderInfoArrayList.add(subOrderInfo);
            });
        }
        //修改原始订单的状态
        updateOrderStatus(orderId, ProcessStatus.SPLIT);

        //返回子订单集合
        return orderInfoArrayList;
    }

    @Override
    public void execExpiredOrder(Long orderId,String flag) {
        // 调用方法 状态
        updateOrderStatus(orderId,ProcessStatus.CLOSED);
        if ("2".equals(flag)){
            // 发送消息队列，关闭支付宝的交易记录。
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }

    @Override
    public void updateCommnetStatus(Long orderId) {
        OrderInfo orderInfo = this.getById(orderId);
        orderInfo.setOrderStatus(ProcessStatus.COMMNET.getOrderStatus().name());
        orderInfo.setProcessStatus(ProcessStatus.COMMNET.name());
        this.updateById(orderInfo);
    }


}
